const { ccclass, property } = cc._decorator;

@ccclass
export default class arrow extends cc.Component {
    @property(cc.SpriteFrame)
    publicArrowList: cc.SpriteFrame[] = [];
    @property(cc.SpriteFrame)
    leaderArrowList: cc.SpriteFrame[] = [];
    @property({
        type: cc.Integer,
        min: 10,
    })
    publicArrowNum = 0;

    private arrowsList: cc.Node[] = [];
    private oldOnTargetStatus: boolean = false;
    public newOnTargetStatus: boolean = false;

    onLoad() { this.createArrows(); }


    update(dt) {
        if (this.oldOnTargetStatus == this.newOnTargetStatus) { return; }
        this.arrowsList.forEach(element => {
            element.getComponent(cc.Sprite).spriteFrame = this.newOnTargetStatus ? this.publicArrowList[1] : this.publicArrowList[0];
        });
        this.arrowsList[this.arrowsList.length - 1].getComponent(cc.Sprite).spriteFrame = this.newOnTargetStatus ? this.leaderArrowList[1] : this.leaderArrowList[0];
        this.oldOnTargetStatus = this.newOnTargetStatus;
    }

    //生成所有箭头
    private createArrows(): void {
        var allArrowNum = this.publicArrowNum + 1;  //总箭头数
        for (let i = 0; i < allArrowNum; i++) {
            var isLeaderArrow = i == (allArrowNum - 1) ? true : false;
            var arrow = new cc.Node().addComponent(cc.Sprite);
            arrow.spriteFrame = isLeaderArrow ? this.leaderArrowList[0] : this.publicArrowList[0];
            arrow.node.scale = isLeaderArrow ? 1 : (0.2 + i / (this.publicArrowNum - 1) * 0.8); //普通箭头一节比一节大
            // arrow.node.anchorY = 1; 每个箭头的锚点可以自己设置 这里默认是箭头中心
            arrow.node.parent = this.node;
            this.arrowsList.push(arrow.node);
        }
    }

    /**
     * 通过起点和终点动态控制箭头位置和角度
     * 在这里应用三阶贝塞尔曲线公式有几个设定:
     * 1、箭头数量确定，所以每个箭头对应的t值固定
     * 2、已有参照曲线，两个控制点也可根据起点终点算出
     */
    public controlArrows(sPos: cc.Vec2, ePos: cc.Vec2): void {
        var [ctrlAPos, ctrlBpos] = this.countCtrlPos(sPos, ePos);

        for (let i = 0; i < this.arrowsList.length; i++) {
            //每个arrows的位置
            var t = i / (this.arrowsList.length - 1);
            var pos = this.third_order_bessel(sPos, ePos, ctrlAPos, ctrlBpos, t);
            this.arrowsList[i].setPosition(pos);

            //每个arrows的角度 这里第一个箭头角度默认不变，如果也想改变第一个箭头的角度可以在上面生成箭头的时候预先插入一个透明箭头
            if (i > 0) {
                var curArrow = this.arrowsList[i];
                var lastArrow = this.arrowsList[i - 1];
                var gap = cc.v3();
                //相邻两个箭头连线的向量
                curArrow.position.sub(lastArrow.position, gap);
                //ccc中cc.pToAngle()方法已经废弃 这里用Math.atan2(y,x)获得向量与X轴之间的弧度 从而算得每个箭头的旋转值
                curArrow.angle = -(90 - Math.atan2(gap.y, gap.x) * 180 / Math.PI);
            }
        }
    }

    /**
     * 计算得到三阶贝塞尔曲线的两个控制点
     * 注意此处公式并不是固定的，而是通过模拟出与目标曲线 (这里是杀戮尖塔)相似的曲线后，根据三阶贝塞尔曲线公式推导算出的
     * 可以微调函数中的0.1/0.3/0.2/0.3来调整具体效果
     * @param sPos 
     * @param ePos 
     */
    private countCtrlPos(sPos: cc.Vec2, ePos: cc.Vec2): cc.Vec2[] {
        var ctrlApos = cc.v2();
        var ctrlBpos = cc.v2();
        ctrlApos.x = sPos.x + (sPos.x - ePos.x) * 0.1;
        ctrlBpos.x = sPos.x - (sPos.x - ePos.x) * 0.3;
        ctrlApos.y = ePos.y - (ePos.y - sPos.y) * 0.2;
        ctrlBpos.y = ePos.y + (ePos.y - sPos.y) * 0.3;
        return [ctrlApos, ctrlBpos];
    }

    /**
     * 三阶贝塞尔曲线的公式 position = startPos*(1-t)*(1-t)*(1-t)
     *                             + 3*ctrlAPos*t*(1-t)*(1-t)
     *                             + 3*ctrlBPos*t*t*(1-t)
     *                             + endPos*t*t*t
     * 
     * @param sPos 起点
     * @param ePos 终点
     * @param ctrlAPos 控制点A
     * @param ctrlBpos 控制点B
     * @param t 起点到终点的百分比 取值0~1
     */
    private third_order_bessel(sPos: cc.Vec2, ePos: cc.Vec2, ctrlAPos: cc.Vec2, ctrlBpos: cc.Vec2, t: number): cc.Vec2 {
        //注意以下用到的向量计算方法中的结果接受变量必须提前赋个cc.Vec2类型的值

        var result1 = cc.v2();
        sPos.mul(Math.pow((1 - t), 3), result1);

        var result2 = cc.v2();
        ePos.mul(Math.pow(t, 3), result2);

        var result3 = cc.v2();
        ctrlAPos.mul(3 * t * Math.pow((1 - t), 2), result3);

        var result4 = cc.v2();
        ctrlBpos.mul(3 * (1 - t) * Math.pow(t, 2), result4);

        var result = cc.v2();
        result1.add(result2).add(result3).add(result4, result);

        return result;
    }

}
